package com.practice.selenium.driver;

import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

import org.openqa.selenium.chrome.ChromeDriverService;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.GeckoDriverService;
import org.openqa.selenium.ie.InternetExplorerDriverService;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.remote.service.DriverService;
import org.openqa.selenium.safari.SafariDriver;
import org.openqa.selenium.safari.SafariDriverService;

import com.practice.selenium.config.OptionConfig;
import com.practice.selenium.config.SeleniumConfig;
import com.practice.selenium.config.WebDriverConfig;

public class DriverServiceFactory {

	private static DriverServiceFactory instance;
	
	protected DriverService driverService;
	
	protected WebDriverConfig webDriverConfig;
	
	protected SeleniumConfig seleniumConfig;
	
	private DriverServiceFactory() {
		seleniumConfig = SeleniumConfig.load();
		
		for (WebDriverConfig webDriverConfig : seleniumConfig.getWebDrivers()) {
			if (webDriverConfig.isUsed()) {
				this.webDriverConfig = webDriverConfig;
				switch (webDriverConfig.getBrowser()) {
				case SeleniumConfig.BROWSER_FIREFOX:
					driverService = createFirefoxDriverService(webDriverConfig);
					break;
				case SeleniumConfig.BROWSER_CHROME:
					driverService = createChromeDriverService(webDriverConfig);
					break;
				case SeleniumConfig.BROWSER_IE:
					driverService = createInternetExplorerDriverService(webDriverConfig);
					break;
				case SeleniumConfig.BROWSER_SAFARI:
					driverService = createSafariDriverService(webDriverConfig);
					break;
				default:
				}
			}
		}
	}
	
	public static DriverServiceFactory getInstance() {
		if (instance == null) {
			instance = new DriverServiceFactory();
		}
		return instance;
	}
	
	private DriverService createFirefoxDriverService(WebDriverConfig webDriverConfig) {
		if (webDriverConfig.getVersion() >= WebDriverUtil.VERSION_FIREFOX_SELENIUM_3) {
			DriverService.Builder<GeckoDriverService, GeckoDriverService.Builder> builder = 
					new GeckoDriverService.Builder();
			if (webDriverConfig.getDriver() != null) {
				builder = builder.usingDriverExecutable(new File(webDriverConfig.getDriver()));
			}
			DriverService service = builder.usingAnyFreePort().build();
			return service;	
		} else {
			return null;
		}
	}
	
	private DriverService createChromeDriverService(WebDriverConfig webDriverConfig) {
		DriverService.Builder<ChromeDriverService, ChromeDriverService.Builder> builder = 
				new ChromeDriverService.Builder();
		if (webDriverConfig.getDriver() != null) {
			builder = builder.usingDriverExecutable(new File(webDriverConfig.getDriver()));
		}
		DriverService service = builder.usingAnyFreePort().build();
		return service;
	}
	
	private DriverService createInternetExplorerDriverService(WebDriverConfig webDriverConfig) {
		DriverService.Builder<InternetExplorerDriverService, InternetExplorerDriverService.Builder> builder = 
				new InternetExplorerDriverService.Builder();
		if (webDriverConfig.getDriver() != null) {
			builder = builder.usingDriverExecutable(new File(webDriverConfig.getDriver()));
		}
		DriverService service = builder.usingAnyFreePort().build();
		return service;
	}
	
	private DriverService createSafariDriverService(WebDriverConfig webDriverConfig) {
		if (webDriverConfig.getVersion() >= WebDriverUtil.VERSION_SAFARI_SELENIUM_3) {
			DriverService.Builder<SafariDriverService, SafariDriverService.Builder> builder = 
					new SafariDriverService.Builder();
			DriverService service = builder.usingAnyFreePort().build();
			return service;
		} else {
			return null;
		}
	}
	
	public void startService() throws IOException {
		if (driverService != null) {
			driverService.start();
		}
	}

	public void stopService() {
		if (driverService != null) {
			driverService.stop();
		}
	}
	
	public RemoteWebDriver createWebDriver() {
		RemoteWebDriver remoteWebDriver = null;
		switch(webDriverConfig.getBrowser()) {
		case SeleniumConfig.BROWSER_FIREFOX:
			if (webDriverConfig.getVersion() >= WebDriverUtil.VERSION_FIREFOX_SELENIUM_3) {
				remoteWebDriver = new RemoteWebDriver(driverService.getUrl(), DesiredCapabilities.firefox());
			} else {
				remoteWebDriver = new FirefoxDriver();
			}
			break;
		case SeleniumConfig.BROWSER_CHROME:
			remoteWebDriver = new RemoteWebDriver(driverService.getUrl(), DesiredCapabilities.chrome());
			break;
		case SeleniumConfig.BROWSER_IE:
			remoteWebDriver = new RemoteWebDriver(driverService.getUrl(), DesiredCapabilities.internetExplorer());
			break;
		case SeleniumConfig.BROWSER_SAFARI:
			if (webDriverConfig.getVersion() >= WebDriverUtil.VERSION_SAFARI_SELENIUM_3) {
				remoteWebDriver = new RemoteWebDriver(driverService.getUrl(), DesiredCapabilities.safari());
			} else {
				remoteWebDriver = new SafariDriver();
			}
			break;
		default:
		}
		
		if (remoteWebDriver != null) {
			manageWebDriver(remoteWebDriver);
		}
		
		return remoteWebDriver;
	}

	private void manageWebDriver(RemoteWebDriver remoteWebDriver) {
		OptionConfig optionConfig = seleniumConfig.getOption();
		remoteWebDriver.manage().window().maximize();
		remoteWebDriver.manage().timeouts().implicitlyWait(optionConfig.getImplicitlyWait(), TimeUnit.SECONDS);
		remoteWebDriver.manage().timeouts().pageLoadTimeout(optionConfig.getPageLoadTimeout(), TimeUnit.SECONDS);
	}
	
}
